here_long <-  -122.3095
here_lat <- 47.6560
seattle = get_map(location = c(here_long, here_lat), zoom = 13, maptype = 'roadmap')
Map from URL : http://maps.googleapis.com/maps/api/staticmap?center=47.656,-122.3095&zoom=13&size=640x640&scale=2&maptype=roadmap&language=en-EN&sensor=false
spd.911 <- spd.911 %>% 
             rowwise() %>% 
             mutate(dist=distVincentyEllipsoid(c(Longitude, Latitude), c(here_long, here_lat)))              
Error in eval(lhs, parent, parent) : object 'spd.911' not found
data <- read.csv('2016-2017-Clean.csv', header = TRUE)
data <- filter(data, !str_detect(Event.Clearance.Description, "HARBOR - DEBRIS, NAVIGATIONAL HAZARDS"))
nrow(data)
[1] 765
ggmap(seattle) +
   geom_point(data = data, aes(x = Longitude, y = Latitude), colour = "red", alpha = 0.75)

  #coord_map()
freq_by_desc <- table(droplevels(data$Event.Clearance.Description))
# View(freq_by_desc)
ggplot(as.data.frame(freq_by_desc), 
       aes(x = Var1, y = Freq)) +
       geom_bar(stat = 'identity') +# create bar plot
    coord_flip()

#Traffic related calls, suspicious circumstances, and disturbances are the the most significant threats to pedestrations
        
ggmap(seattle) +
  geom_point(data = data, aes(x = Longitude, y = Latitude, group = Event.Clearance.Description, color = Event.Clearance.Description), alpha = 0.5, size = 10) +
  facet_wrap(~ Event.Clearance.Description) +
  theme(axis.ticks = element_blank(), 
        axis.text.x = element_blank(),
        axis.text.y = element_blank(),
        strip.text = element_text(size=50),
        legend.position = "none"
        )

# selecting just ID and location data
df_loc <- data %>% dplyr::select(CAD.CDW.ID, Longitude, Latitude)
# figuring out number of clusters
wss <- c()
# clusters 1 to 15
for (i in 1:15) {
  wss[i] <- sum(kmeans(df_loc, centers=i)$withinss)
}
plot(1:15, wss, type="b", xlab="Number of Clusters",
  ylab="Within groups sum of squares")

# fitting model
fit <- kmeans(df_loc, 10)
fit$centers # look at cluster sizes and means. want clusters to be about equal size
   CAD.CDW.ID Longitude Latitude
1     1966835 -122.3188 47.65906
2     2093969 -122.3142 47.65982
3     2116300 -122.3129 47.66095
4     1899308 -122.3154 47.66025
5     2046956 -122.3160 47.65922
6     2071185 -122.3156 47.66114
7     1864428 -122.3118 47.66149
8     2022152 -122.3172 47.66033
9     1994531 -122.3159 47.66109
10    1932836 -122.3171 47.66133
fit$cluster
  [1]  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7
 [40]  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7
 [79]  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  7  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4
[118]  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4
[157]  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4  4 10 10 10 10 10 10 10 10
[196] 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
[235] 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
[274] 10 10 10 10 10 10 10 10 10  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1
[313]  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1
[352]  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9
[391]  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9  9
[430]  9  9  9  9  9  9  9  9  9  9  9  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8
[469]  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8  8
[508]  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5
[547]  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  5  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6
[586]  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6  6
[625]  6  6  6  6  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2
[664]  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  2  3  3  3  3  3  3  3  3
[703]  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3
[742]  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3  3
cluster.size <- data.frame(1:10, fit$size)
cluster.size
ggplot(data = cluster.size, aes(x = X1.10, y = fit.size)) +
  geom_bar(stat = 'identity')

ggplot()

ggmap(seattle) +
  geom_point(data = as.data.frame(fit$centers), aes(x = Longitude, y = Latitude), alpha = 0.5)

# looking at cluster means
aggregate(df_loc, by=list(fit$cluster), FUN=mean)
df_loc
# adding data back into dataframe 
# df_loc <- df_loc %>% mutate(cluster = fit$cluster) 
# View(data)
# hundred block vs TOD
  
by_hr <- table(data$event_clearance_hr)
by_hr

  0   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15  16  17  18  19  20  21  22  23 
 38  28  31  52  20  16  17  15  14  16  12  36  20  32  36  39  43  24  25 115  21  38  40  37 
ggplot(as.data.frame(by_hr), aes(x = Var1, y = Freq)) + 
  geom_point() +
  xlab('hour of day')

ggplot(data, aes(x = event_clearance_ts, y = time_until_event_clear)) + 
  geom_point(alpha = 0.25)

ggplot(data, aes(x = Hundred.Block.Location, y = time_until_event_clear)) + 
  geom_point(alpha = 0.25)

  
# selecting just ID and location data
df_loc <- data.w.at.scene %>% dplyr::select(CAD.CDW.ID, Latitude, Longitude)
Error in eval(lhs, parent, parent) : object 'data.w.at.scene' not found
#some useful functions for performing clustering
#extract the lat and long from a dataframe, and run kmeans on it
# x = one of our dataframes
# clusters = how many centers you want kmeans to work with when clustering
fit.clusters <- function(x, clusters) {
  # selecting just ID and location data
  df_loc <- x %>% dplyr::select(CAD.CDW.ID, Latitude, Longitude)
  # fitting model
  fit <- kmeans(df_loc, clusters)
  fit$centers # look at cluster sizes and means. want clusters to be about equal size
  return(fit)
}
#make a plot that will tell you how many clusters might work for a given dataframe
# x = a dataframe
# max = the maximum number of clusters you want to try
find.num.clusters <- function(x, max) {
  if(max > nrow(x)) { stop('Cannot fit more clusters than there are rows in dataframe')}
  df_loc <- x %>% dplyr::select(CAD.CDW.ID, Latitude, Longitude)
  wss = c()
  for (i in 1:max) {
    wss[i] <- sum(kmeans(df_loc, centers=i)$withinss)
  }
  plot(1:max, wss, type="b", xlab="Number of Clusters",
     ylab="Within groups sum of squares")
}
#plot the number of observations in each cluster
# x = a fit object returned from kmeans() or the fit.clusters() function above
plot.cluster.sizes <- function(x) {
  cluster.size <- data.frame(data.frame('clusters' = 1:nrow(x$centers), x$size))
  ggplot(data = cluster.size, aes(x = clusters, y = x.size)) +
  geom_bar(stat = 'identity')
}

Clustering by time of day

morning <- filter(data, 6 <= at_scene_time_hr, at_scene_time_hr < 10 )
mid.day <-  filter(data, 10 <= at_scene_time_hr, at_scene_time_hr < 14 )
afternoon <-  filter(data, 14 <= at_scene_time_hr, at_scene_time_hr < 18 )
evening <-  filter(data, 18 <= at_scene_time_hr, at_scene_time_hr < 22 )
night <-  filter(data, 22 <= at_scene_time_hr | at_scene_time_hr < 2 )
early.morning <-  filter(data, 2 <= at_scene_time_hr, at_scene_time_hr < 6 )
ggmap(seattle) +
  geom_point(data = morning, aes(x = Longitude, y = Latitude), alpha = 0.5)

ggmap(seattle) +
  geom_point(data = mid.day, aes(x = Longitude, y = Latitude), alpha = 0.5)

ggmap(seattle) +
  geom_point(data = afternoon, aes(x = Longitude, y = Latitude), alpha = 0.5)

ggmap(seattle) +
  geom_point(data = evening, aes(x = Longitude, y = Latitude), alpha = 0.5)

ggmap(seattle) +
  geom_point(data = night, aes(x = Longitude, y = Latitude), alpha = 0.5)

ggmap(seattle) +
  geom_point(data = early.morning, aes(x = Longitude, y = Latitude), alpha = 0.5)

lengths <- c(nrow(morning), nrow(mid.day), nrow(afternoon), nrow(evening), nrow(night), nrow(early.morning))
names <- c('Morning\n6:00 - 9:59', 'Mid-day\n10:00 - 1:59', 'Afternoon\n2:00 - 5:59', 'Evening\n6:00 - 9:59', 'Night\n10:00 - 1:59', 'Early Morning\n2:00 - 5:59')
by.tod <- data.frame('TOD' = names, 'Count.Crimes' = lengths)
by.tod$TOD = factor(by.tod$TOD, levels = by.tod$TOD)
ggplot(by.tod, aes(x = TOD, y = Count.Crimes)) +
  geom_histogram(stat = 'identity')
Ignoring unknown parameters: binwidth, bins, pad

# find the mode of numeric/character data
Mode <- function(x) {
  ux <- unique(x)
  tab <- tabulate(match(x, ux)); ux[tab == max(tab)]
}
tod.mean <- mean(data$at_scene_time_hr)
tod.med <- median(data$at_scene_time_hr)
tod.mean
[1] 13.28889
tod.med
[1] 14
Mode(data$at_scene_time_hr)
[1] 17
#What is the most common crime committed at each period?
Mode(morning$Event.Clearance.Description)
[1] CRISIS COMPLAINT - GENERAL
7 Levels: ARMED ROBBERY CRISIS COMPLAINT - GENERAL FIGHT DISTURBANCE ... STRONG ARM ROBBERY
Mode(mid.day$Event.Clearance.Description)
[1] CRISIS COMPLAINT - GENERAL
7 Levels: ARMED ROBBERY CRISIS COMPLAINT - GENERAL FIGHT DISTURBANCE ... STRONG ARM ROBBERY
Mode(afternoon$Event.Clearance.Description)
[1] CRISIS COMPLAINT - GENERAL
7 Levels: ARMED ROBBERY CRISIS COMPLAINT - GENERAL FIGHT DISTURBANCE ... STRONG ARM ROBBERY
Mode(evening$Event.Clearance.Description)
[1] CRISIS COMPLAINT - GENERAL
7 Levels: ARMED ROBBERY CRISIS COMPLAINT - GENERAL FIGHT DISTURBANCE ... STRONG ARM ROBBERY
Mode(night$Event.Clearance.Description)
[1] CRISIS COMPLAINT - GENERAL
7 Levels: ARMED ROBBERY CRISIS COMPLAINT - GENERAL FIGHT DISTURBANCE ... STRONG ARM ROBBERY
Mode(early.morning$Event.Clearance.Description)
[1] CRISIS COMPLAINT - GENERAL
7 Levels: ARMED ROBBERY CRISIS COMPLAINT - GENERAL FIGHT DISTURBANCE ... STRONG ARM ROBBERY
#fit kmeans clustering to each time period.
nrow(morning)
[1] 74
find.num.clusters(morning, 10)

fit <- fit.clusters(morning, 10)
ggmap(seattle) +
  geom_point(data = as.data.frame(fit$centers), aes(x = Longitude, y = Latitude), alpha = 0.5)

# looking at cluster means
plot.cluster.sizes(fit)

find.num.clusters(afternoon, 10)

fit <- fit.clusters(mid.day, 10)
ggmap(seattle) +
  geom_point(data = as.data.frame(fit$centers), aes(x = Longitude, y = Latitude), alpha = 0.5)

# looking at cluster means
plot.cluster.sizes(fit)

nrow(afternoon)
[1] 176
find.num.clusters(afternoon, 10)

fit <- fit.clusters(afternoon, 10)
ggmap(seattle) +
  geom_point(data = as.data.frame(fit$centers), aes(x = Longitude, y = Latitude), alpha = 0.5)

# looking at cluster means
plot.cluster.sizes(fit)

find.num.clusters(evening, 10)

fit <- fit.clusters(evening, 10)
ggmap(seattle) +
  geom_point(data = as.data.frame(fit$centers), aes(x = Longitude, y = Latitude), alpha = 0.5)

# looking at cluster means
plot.cluster.sizes(fit)

find.num.clusters(night, 10)

fit <- fit.clusters(night, 10)
ggmap(seattle) +
  geom_point(data = as.data.frame(fit$centers), aes(x = Longitude, y = Latitude), alpha = 0.5)

# looking at cluster means
plot.cluster.sizes(fit)

#take out general crisis complaint - general
data <- filter(data, Event.Clearance.Description != 'CRISIS COMPLAINT - GENERAL')
morning <- filter(data, 6 <= at_scene_time_hr, at_scene_time_hr < 10 )
mid.day <-  filter(data, 10 <= at_scene_time_hr, at_scene_time_hr < 14 )
afternoon <-  filter(data, 14 <= at_scene_time_hr, at_scene_time_hr < 18 )
evening <-  filter(data, 18 <= at_scene_time_hr, at_scene_time_hr < 22 )
night <-  filter(data, 22 <= at_scene_time_hr | at_scene_time_hr < 2 )
early.morning <-  filter(data, 2 <= at_scene_time_hr, at_scene_time_hr < 6 )
ggmap(seattle) +
  geom_point(data = morning, aes(x = Longitude, y = Latitude), alpha = 0.5)

ggmap(seattle) +
  geom_point(data = mid.day, aes(x = Longitude, y = Latitude), alpha = 0.5)

ggmap(seattle) +
  geom_point(data = afternoon, aes(x = Longitude, y = Latitude), alpha = 0.5)

ggmap(seattle) +
  geom_point(data = evening, aes(x = Longitude, y = Latitude), alpha = 0.5)

ggmap(seattle) +
  geom_point(data = night, aes(x = Longitude, y = Latitude), alpha = 0.5)

ggmap(seattle) +
  geom_point(data = early.morning, aes(x = Longitude, y = Latitude), alpha = 0.5)

lengths <- c(nrow(morning), nrow(mid.day), nrow(afternoon), nrow(evening), nrow(night), nrow(early.morning))
names <- c('Morning\n6:00 - 9:59', 'Mid-day\n10:00 - 1:59', 'Afternoon\n2:00 - 5:59', 'Evening\n6:00 - 9:59', 'Night\n10:00 - 1:59', 'Early Morning\n2:00 - 5:59')
by.tod <- data.frame('TOD' = names, 'Count.Crimes' = lengths)
by.tod$TOD = factor(by.tod$TOD, levels = by.tod$TOD)
ggplot(by.tod, aes(x = TOD, y = Count.Crimes)) +
  geom_histogram(stat = 'identity')
Ignoring unknown parameters: binwidth, bins, pad

# find the mode of numeric/character data
Mode <- function(x) {
  ux <- unique(x)
  tab <- tabulate(match(x, ux)); ux[tab == max(tab)]
}
tod.mean <- mean(data$at_scene_time_hr)
tod.med <- median(data$at_scene_time_hr)
tod.mean
[1] 13.69318
tod.med
[1] 14
Mode(data$at_scene_time_hr)
[1] 17
#What is the most common crime committed at each period?
Mode(morning$Event.Clearance.Description)
[1] HAZARDS
7 Levels: ARMED ROBBERY CRISIS COMPLAINT - GENERAL FIGHT DISTURBANCE ... STRONG ARM ROBBERY
Mode(mid.day$Event.Clearance.Description)
[1] HARASSMENT, THREATS
7 Levels: ARMED ROBBERY CRISIS COMPLAINT - GENERAL FIGHT DISTURBANCE ... STRONG ARM ROBBERY
Mode(afternoon$Event.Clearance.Description)
[1] HARASSMENT, THREATS
7 Levels: ARMED ROBBERY CRISIS COMPLAINT - GENERAL FIGHT DISTURBANCE ... STRONG ARM ROBBERY
Mode(evening$Event.Clearance.Description)
[1] HARASSMENT, THREATS
7 Levels: ARMED ROBBERY CRISIS COMPLAINT - GENERAL FIGHT DISTURBANCE ... STRONG ARM ROBBERY
Mode(night$Event.Clearance.Description)
[1] HARASSMENT, THREATS FIGHT DISTURBANCE  
7 Levels: ARMED ROBBERY CRISIS COMPLAINT - GENERAL FIGHT DISTURBANCE ... STRONG ARM ROBBERY
Mode(early.morning$Event.Clearance.Description)
[1] STRONG ARM ROBBERY
7 Levels: ARMED ROBBERY CRISIS COMPLAINT - GENERAL FIGHT DISTURBANCE ... STRONG ARM ROBBERY
#fit kmeans clustering to each time period.
nrow(morning)
[1] 48
find.num.clusters(morning, 10)

fit <- fit.clusters(morning, 10)
ggmap(seattle) +
  geom_point(data = as.data.frame(fit$centers), aes(x = Longitude, y = Latitude), alpha = 0.5)

# looking at cluster means
plot.cluster.sizes(fit)

find.num.clusters(afternoon, 10)

fit <- fit.clusters(mid.day, 10)
ggmap(seattle) +
  geom_point(data = as.data.frame(fit$centers), aes(x = Longitude, y = Latitude), alpha = 0.5)

# looking at cluster means
plot.cluster.sizes(fit)

nrow(afternoon)
[1] 107
find.num.clusters(afternoon, 10)

fit <- fit.clusters(afternoon, 10)
ggmap(seattle) +
  geom_point(data = as.data.frame(fit$centers), aes(x = Longitude, y = Latitude), alpha = 0.5)

# looking at cluster means
plot.cluster.sizes(fit)

find.num.clusters(evening, 10)

fit <- fit.clusters(evening, 10)
ggmap(seattle) +
  geom_point(data = as.data.frame(fit$centers), aes(x = Longitude, y = Latitude), alpha = 0.5)

# looking at cluster means
plot.cluster.sizes(fit)

find.num.clusters(night, 10)

fit <- fit.clusters(night, 10)
ggmap(seattle) +
  geom_point(data = as.data.frame(fit$centers), aes(x = Longitude, y = Latitude), alpha = 0.5)

# looking at cluster means
plot.cluster.sizes(fit)

LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQotLS0KdGl0bGU6ICJSIE5vdGVib29rIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgpgYGB7ciBzZXR1cH0KIyBpbnN0YWxsLnBhY2thZ2VzKCJ0aWR5dmVyc2UiKTsKIyBpbnN0YWxsLnBhY2thZ2VzKCJyZ2RhbCIpOwpsaWJyYXJ5KHRpZHl2ZXJzZSkKcmVxdWlyZSgibWFwcyIpCmxpYnJhcnkoZ2Vvc3BoZXJlKQpsaWJyYXJ5KHN0cmluZ3IpCmxpYnJhcnkocmdkYWwpCmxpYnJhcnkoY2FyZXQpCmxpYnJhcnkobHVicmlkYXRlKQpsaWJyYXJ5KG1hcHRvb2xzKQppZiAoIXJlcXVpcmUoZ2dtYXApKSB7IGluc3RhbGwucGFja2FnZXMoJ2dnbWFwJyk7IHJlcXVpcmUoZ2dtYXApIH0KbGlicmFyeShnZ21hcCkKcGF0aC50by5jc3YgPC0gJ34vRG93bmxvYWRzL1NlYXR0bGVfUG9saWNlX0RlcGFydG1lbnRfOTExX0luY2lkZW50X1Jlc3BvbnNlLmNzdicKc3BkLjkxMSA8LSByZWFkLmNzdihwYXRoLnRvLmNzdiwgaGVhZGVyID0gVFJVRSkKCnNwZC45MTEkY2xlYXJhbmNlX2RhdGVfdHMgPSBhcy5QT1NJWGN0KHN0cnB0aW1lKHNwZC45MTEkRXZlbnQuQ2xlYXJhbmNlLkRhdGUsICIlbS8lZC8lWSAlSTolTTolUyAlcCIpKQpzcGQuOTExJGNsZWFyYW5jZV9kYXRlX2RhdGUgPSBhcy5EYXRlKHNwZC45MTEkY2xlYXJhbmNlX2RhdGVfdHMpCnNwZC45MTEkZXZlbnRfY2xlYXJhbmNlX3RzID0gYXMuUE9TSVhjdChzdHJwdGltZShzcGQuOTExJEV2ZW50LkNsZWFyYW5jZS5EYXRlLCAiJW0vJWQvJVkgJUk6JU06JVMgJXAiKSkKc3BkLjkxMSRldmVudF9jbGVhcmFuY2VfZGF0ZSA9IGFzLkRhdGUoc3BkLjkxMSRldmVudF9jbGVhcmFuY2VfdHMpCnNwZC45MTEkZXZlbnRfY2xlYXJhbmNlX21vbnRoID0gbW9udGgoeW1kX2htcyhhcy5jaGFyYWN0ZXIoc3BkLjkxMSRldmVudF9jbGVhcmFuY2VfdHMpKSkKc3BkLjkxMSRldmVudF9jbGVhcmFuY2VfZGF5ID0gd2Vla2RheXMoc3BkLjkxMSRldmVudF9jbGVhcmFuY2VfZGF0ZSkKc3BkLjkxMSRldmVudF9jbGVhcmFuY2VfaHIgPSBob3VyKHltZF9obXMoYXMuY2hhcmFjdGVyKHNwZC45MTEkZXZlbnRfY2xlYXJhbmNlX3RzKSkpCnNwZC45MTEkZXZlbnRfY2xlYXJhbmNlX21uID0gbWludXRlKHltZF9obXMoYXMuY2hhcmFjdGVyKHNwZC45MTEkZXZlbnRfY2xlYXJhbmNlX3RzKSkpCnNwZC45MTEkSW5pdGlhbC5UeXBlLkdyb3VwID0gZmFjdG9yKHNwZC45MTEkSW5pdGlhbC5UeXBlLkdyb3VwKQpzcGQuOTExJEV2ZW50LkNsZWFyYW5jZS5Hcm91cCA9IGZhY3RvcihzcGQuOTExJEV2ZW50LkNsZWFyYW5jZS5Hcm91cCkKc3BkLjkxMSRab25lLkJlYXQgPSBmYWN0b3Ioc3BkLjkxMSRab25lLkJlYXQpCnNwZC45MTEkRGlzdHJpY3QuU2VjdG9yID0gZmFjdG9yKHNwZC45MTEkRGlzdHJpY3QuU2VjdG9yKQpzcGQuOTExJGV2ZW50X2NsZWFyYW5jZV9kYXkgPSBmYWN0b3Ioc3BkLjkxMSRldmVudF9jbGVhcmFuY2VfZGF5KQoKc3BkLjkxMSRhdF9zY2VuZV90aW1lX3RzID0gYXMuUE9TSVhjdChzdHJwdGltZShzcGQuOTExJEF0LlNjZW5lLlRpbWUsICIlbS8lZC8lWSAlSTolTTolUyAlcCIpKSAjY29udmVydGluZyB0aW1lIGZyb20gU3RyaW5nIHRvIGRhdGUgYW5kIHRpbWUgcmVwcmVzZW50YXRpb24gKFBPU0lYY3QpCnNwZC45MTEkYXRfc2NlbmVfdGltZV9ociA9IGhvdXIoeW1kX2htcyhhcy5jaGFyYWN0ZXIoc3BkLjkxMSRhdF9zY2VuZV90aW1lX3RzKSkpCnNwZC45MTEkYXRfc2NlbmVfdGltZV9kYXRlID0gYXMuRGF0ZShzcGQuOTExJGF0X3NjZW5lX3RpbWVfdHMpCnNwZC45MTEkdGltZV91bnRpbF9ldmVudF9jbGVhciA9IGFzLm51bWVyaWMoc3BkLjkxMSRldmVudF9jbGVhcmFuY2VfdHMgLSBzcGQuOTExJGF0X3NjZW5lX3RpbWVfdHMpCgoKCiMgcGF0aCB0byB0aGUgRk9MREVSIHdpdGggdGhlIC5zaHAgZmlsZSBpbiBpdC4gdGhlIHNlY29uZCBwYXJhbSBpcyB0aGUgbmFtZSBvZiB0aGUgLnNocCBmaWxlCiMgc2VhdHRsZSA8LSByZWFkT0dSKGRzbiA9IHBhdGguZXhwYW5kKCJ+L2RvY3VtZW50cy9JTkZPMzcwL3Byb2plY3QtdGVhbW5hbWUtdjIvbWFwcy1hcGktdGVzdCIpLCBsYXllciA9ICJTZWF0dGxlX0NpdHlfTGltaXRzIikKCiMgdXNhIDwtIG1hcF9kYXRhKCJzdGF0ZSIpCiMgZGF0YSA8LSBtZXJnZSh1c2EsIHNwZC45MTEpCiMgUmVkIFNxdWFyZSBjb29yZGluYXRlcwpoZXJlX2xvbmcgPC0gIC0xMjIuMzA5NQpoZXJlX2xhdCA8LSA0Ny42NTYwCgpzZWF0dGxlID0gZ2V0X21hcChsb2NhdGlvbiA9IGMoaGVyZV9sb25nLCBoZXJlX2xhdCksIHpvb20gPSAxMywgbWFwdHlwZSA9ICdyb2FkbWFwJykKCmBgYAoKCmBgYHtyfQpzcGQuOTExIDwtIHNwZC45MTEgJT4lIAogICAgICAgICAgICAgcm93d2lzZSgpICU+JSAKICAgICAgICAgICAgIG11dGF0ZShkaXN0PWRpc3RWaW5jZW50eUVsbGlwc29pZChjKExvbmdpdHVkZSwgTGF0aXR1ZGUpLCBjKGhlcmVfbG9uZywgaGVyZV9sYXQpKSkgICAgICAgICAgICAgIApucm93KHNwZC45MTEpCgpkZXNjcmlwdGlvbnMgPC0gYygiU1RST05HIEFSTSBST0JCRVJZIiwgIlBFUlNPTiBXSVRIIEEgV0VBUE9OIChOT1QgR1VOKSIsICJIQVpBUkRTIiwgIkhBUkFTU01FTlQsIFRIUkVBVFMiLCAiRklHSFQgRElTVFVSQkFOQ0UiLCAiQ1JJU0lTIENPTVBMQUlOVCAtIEdFTkVSQUwiLCAiQVJNRUQgUk9CQkVSWSIpCgojIFJlbW92ZXMgU3BlY2lmaWNhbGx5IEhhcmFzc21lbnQgYnkgVGVsZXBob25lIGFuZCBXcml0aW5nLCBhcyB3ZWxsIGFzIG90aGVyIG5vbi1zY2FyeSBjcmltZXMKZGF0YS5wZWQgPC0gc3BkLjkxMSAlPiUgZmlsdGVyKHN0cl9kZXRlY3QoRXZlbnQuQ2xlYXJhbmNlLkRlc2NyaXB0aW9uLCBwYXN0ZShkZXNjcmlwdGlvbnMsIGNvbGxhcHNlPSJ8IikpKSAlPiUgZmlsdGVyKCFzdHJfZGV0ZWN0KEV2ZW50LkNsZWFyYW5jZS5EZXNjcmlwdGlvbiwgIkhBUkFTU01FTlQsIFRIUkVBVFMgLSBCWSBURUxFUEhPTkUsIFdSSVRJTkciKSkgJT4lIGZpbHRlcighc3RyX2RldGVjdChFdmVudC5DbGVhcmFuY2UuRGVzY3JpcHRpb24sICJIQVJCT1IgREVCUklTLCBOQVZJR0FUSU9OQUwgSEFaQVJEUyIpKQojIGRhdGEucGVkIDwtIGRhdGEubm93Cm5yb3coZGF0YS5wZWQpCgpkYXRhLmhlcmUgPC0gZGF0YS5wZWQgJT4lIGZpbHRlcihkaXN0IDwgMjYwMCkKCgoKCgpkYXRhLncuYXQuc2NlbmUgPC0gZmlsdGVyKGRhdGEuaGVyZSwgIWlzLm5hKGF0X3NjZW5lX3RpbWVfZGF0ZSkpCmRhdGEgPC0gZGF0YS53LmF0LnNjZW5lCm5yb3coZGF0YSkKIyBWaWV3KGRhdGEpCgojIHdyaXRlLmNzdihkYXRhLCAnMjAxNi0yMDE3LUNsZWFuLmNzdicpCmBgYAoKYGBge3J9CmRhdGEgPC0gcmVhZC5jc3YoJzIwMTYtMjAxNy1DbGVhbi5jc3YnLCBoZWFkZXIgPSBUUlVFKQoKZGF0YSA8LSBmaWx0ZXIoZGF0YSwgIXN0cl9kZXRlY3QoRXZlbnQuQ2xlYXJhbmNlLkRlc2NyaXB0aW9uLCAiSEFSQk9SIC0gREVCUklTLCBOQVZJR0FUSU9OQUwgSEFaQVJEUyIpKQpucm93KGRhdGEpCmdnbWFwKHNlYXR0bGUpICsKICAgZ2VvbV9wb2ludChkYXRhID0gZGF0YSwgYWVzKHggPSBMb25naXR1ZGUsIHkgPSBMYXRpdHVkZSksIGNvbG91ciA9ICJyZWQiLCBhbHBoYSA9IDAuNzUpCiAgI2Nvb3JkX21hcCgpCgpgYGAKCmBgYHtyfQpmcmVxX2J5X2Rlc2MgPC0gdGFibGUoZHJvcGxldmVscyhkYXRhJEV2ZW50LkNsZWFyYW5jZS5EZXNjcmlwdGlvbikpCiMgVmlldyhmcmVxX2J5X2Rlc2MpCgpnZ3Bsb3QoYXMuZGF0YS5mcmFtZShmcmVxX2J5X2Rlc2MpLCAKICAgICAgIGFlcyh4ID0gVmFyMSwgeSA9IEZyZXEpKSArCiAgICAgICBnZW9tX2JhcihzdGF0ID0gJ2lkZW50aXR5JykgKyMgY3JlYXRlIGJhciBwbG90CiAgICBjb29yZF9mbGlwKCkKCiNUcmFmZmljIHJlbGF0ZWQgY2FsbHMsIHN1c3BpY2lvdXMgY2lyY3Vtc3RhbmNlcywgYW5kIGRpc3R1cmJhbmNlcyBhcmUgdGhlIHRoZSBtb3N0IHNpZ25pZmljYW50IHRocmVhdHMgdG8gcGVkZXN0cmF0aW9ucwoKICAgICAgICAKYGBgCgpgYGB7ciBmaWcuaGVpZ2h0PTIwLCBmaWcud2lkdGg9MjB9CmdnbWFwKHNlYXR0bGUpICsKICBnZW9tX3BvaW50KGRhdGEgPSBkYXRhLCBhZXMoeCA9IExvbmdpdHVkZSwgeSA9IExhdGl0dWRlLCBncm91cCA9IEV2ZW50LkNsZWFyYW5jZS5EZXNjcmlwdGlvbiwgY29sb3IgPSBFdmVudC5DbGVhcmFuY2UuRGVzY3JpcHRpb24pLCBhbHBoYSA9IDAuNSwgc2l6ZSA9IDEwKSArCiAgZmFjZXRfd3JhcCh+IEV2ZW50LkNsZWFyYW5jZS5EZXNjcmlwdGlvbikgKwogIHRoZW1lKGF4aXMudGlja3MgPSBlbGVtZW50X2JsYW5rKCksIAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT01MCksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiCiAgICAgICAgKQpgYGAKCmBgYHtyfQojIHNlbGVjdGluZyBqdXN0IElEIGFuZCBsb2NhdGlvbiBkYXRhCmRmX2xvYyA8LSBkYXRhICU+JSBkcGx5cjo6c2VsZWN0KENBRC5DRFcuSUQsIExvbmdpdHVkZSwgTGF0aXR1ZGUpCgojIGZpZ3VyaW5nIG91dCBudW1iZXIgb2YgY2x1c3RlcnMKd3NzIDwtIGMoKQojIGNsdXN0ZXJzIDEgdG8gMTUKZm9yIChpIGluIDE6MTUpIHsKICB3c3NbaV0gPC0gc3VtKGttZWFucyhkZl9sb2MsIGNlbnRlcnM9aSkkd2l0aGluc3MpCn0KcGxvdCgxOjE1LCB3c3MsIHR5cGU9ImIiLCB4bGFiPSJOdW1iZXIgb2YgQ2x1c3RlcnMiLAogIHlsYWI9IldpdGhpbiBncm91cHMgc3VtIG9mIHNxdWFyZXMiKQoKIyBmaXR0aW5nIG1vZGVsCmZpdCA8LSBrbWVhbnMoZGZfbG9jLCAxMCkKZml0JGNlbnRlcnMgIyBsb29rIGF0IGNsdXN0ZXIgc2l6ZXMgYW5kIG1lYW5zLiB3YW50IGNsdXN0ZXJzIHRvIGJlIGFib3V0IGVxdWFsIHNpemUKZml0JGNsdXN0ZXIKY2x1c3Rlci5zaXplIDwtIGRhdGEuZnJhbWUoMToxMCwgZml0JHNpemUpCmNsdXN0ZXIuc2l6ZQoKZ2dwbG90KGRhdGEgPSBjbHVzdGVyLnNpemUsIGFlcyh4ID0gWDEuMTAsIHkgPSBmaXQuc2l6ZSkpICsKICBnZW9tX2JhcihzdGF0ID0gJ2lkZW50aXR5JykKZ2dwbG90KCkKZ2dtYXAoc2VhdHRsZSkgKwogIGdlb21fcG9pbnQoZGF0YSA9IGFzLmRhdGEuZnJhbWUoZml0JGNlbnRlcnMpLCBhZXMoeCA9IExvbmdpdHVkZSwgeSA9IExhdGl0dWRlKSwgYWxwaGEgPSAwLjUpCiMgbG9va2luZyBhdCBjbHVzdGVyIG1lYW5zCmFnZ3JlZ2F0ZShkZl9sb2MsIGJ5PWxpc3QoZml0JGNsdXN0ZXIpLCBGVU49bWVhbikKCmRmX2xvYwoKIyBhZGRpbmcgZGF0YSBiYWNrIGludG8gZGF0YWZyYW1lIAojIGRmX2xvYyA8LSBkZl9sb2MgJT4lIG11dGF0ZShjbHVzdGVyID0gZml0JGNsdXN0ZXIpIAoKIyBWaWV3KGRhdGEpCmBgYAoKYGBge3J9CiMgZGlzdHJpYnV0aW9uIG9mIGNyaW1lcyBieSBtb250aApieV9tb250aCA8LSB0YWJsZShkYXRhJGV2ZW50X2NsZWFyYW5jZV9tb250aCkKYGBgCgpgYGB7cn0KIyBodW5kcmVkIGJsb2NrIHZzIFRPRAogIApieV9ociA8LSB0YWJsZShkYXRhJGV2ZW50X2NsZWFyYW5jZV9ocikKYnlfaHIKZ2dwbG90KGFzLmRhdGEuZnJhbWUoYnlfaHIpLCBhZXMoeCA9IFZhcjEsIHkgPSBGcmVxKSkgKyAKICBnZW9tX3BvaW50KCkgKwogIHhsYWIoJ2hvdXIgb2YgZGF5JykKCgoKZ2dwbG90KGRhdGEsIGFlcyh4ID0gZXZlbnRfY2xlYXJhbmNlX3RzLCB5ID0gdGltZV91bnRpbF9ldmVudF9jbGVhcikpICsgCiAgZ2VvbV9wb2ludChhbHBoYSA9IDAuMjUpCgpnZ3Bsb3QoZGF0YSwgYWVzKHggPSBIdW5kcmVkLkJsb2NrLkxvY2F0aW9uLCB5ID0gdGltZV91bnRpbF9ldmVudF9jbGVhcikpICsgCiAgZ2VvbV9wb2ludChhbHBoYSA9IDAuMjUpCiAgCgojIHNlbGVjdGluZyBqdXN0IElEIGFuZCBsb2NhdGlvbiBkYXRhCmRmX2xvYyA8LSBkYXRhLncuYXQuc2NlbmUgJT4lIGRwbHlyOjpzZWxlY3QoQ0FELkNEVy5JRCwgTGF0aXR1ZGUsIExvbmdpdHVkZSkKCiMgZmlndXJpbmcgb3V0IG51bWJlciBvZiBjbHVzdGVycwp3c3MgPC0gYygpCiMgY2x1c3RlcnMgMSB0byAxNQpmb3IgKGkgaW4gMToxNSkgewogIHdzc1tpXSA8LSBzdW0oa21lYW5zKGRmX2xvYywgY2VudGVycz1pKSR3aXRoaW5zcykKfQpwbG90KDE6MTUsIHdzcywgdHlwZT0iYiIsIHhsYWI9Ik51bWJlciBvZiBDbHVzdGVycyIsCiAgeWxhYj0iV2l0aGluIGdyb3VwcyBzdW0gb2Ygc3F1YXJlcyIpCgojIGZpdHRpbmcgbW9kZWwKZml0IDwtIGttZWFucyhkZl9sb2MsIDUpCmZpdCRjZW50ZXJzICMgbG9vayBhdCBjbHVzdGVyIHNpemVzIGFuZCBtZWFucy4gd2FudCBjbHVzdGVycyB0byBiZSBhYm91dCBlcXVhbCBzaXplCmZpdCRjbHVzdGVyCmNsdXN0ZXIuc2l6ZSA8LSBkYXRhLmZyYW1lKDE6NSwgZml0JHNpemUpCmNsdXN0ZXIuc2l6ZQoKZ2dwbG90KGRhdGEgPSBjbHVzdGVyLnNpemUsIGFlcyh4ID0gWDEuNSwgeSA9IGZpdC5zaXplKSkgKwogIGdlb21fYmFyKHN0YXQgPSAnaWRlbnRpdHknKQpnZ3Bsb3QoKQpnZ21hcChzZWF0dGxlKSArCiAgZ2VvbV9wb2ludChkYXRhID0gYXMuZGF0YS5mcmFtZShmaXQkY2VudGVycyksIGFlcyh4ID0gTG9uZ2l0dWRlLCB5ID0gTGF0aXR1ZGUpLCBhbHBoYSA9IDAuNSkKIyBsb29raW5nIGF0IGNsdXN0ZXIgbWVhbnMKYWdncmVnYXRlKGRmX2xvYywgYnk9bGlzdChmaXQkY2x1c3RlciksIEZVTj1tZWFuKQoKZGZfbG9jCmBgYAoKYGBge3J9CiNzb21lIHVzZWZ1bCBmdW5jdGlvbnMgZm9yIHBlcmZvcm1pbmcgY2x1c3RlcmluZwoKI2V4dHJhY3QgdGhlIGxhdCBhbmQgbG9uZyBmcm9tIGEgZGF0YWZyYW1lLCBhbmQgcnVuIGttZWFucyBvbiBpdAojIHggPSBvbmUgb2Ygb3VyIGRhdGFmcmFtZXMKIyBjbHVzdGVycyA9IGhvdyBtYW55IGNlbnRlcnMgeW91IHdhbnQga21lYW5zIHRvIHdvcmsgd2l0aCB3aGVuIGNsdXN0ZXJpbmcKZml0LmNsdXN0ZXJzIDwtIGZ1bmN0aW9uKHgsIGNsdXN0ZXJzKSB7CiAgIyBzZWxlY3RpbmcganVzdCBJRCBhbmQgbG9jYXRpb24gZGF0YQogIGRmX2xvYyA8LSB4ICU+JSBkcGx5cjo6c2VsZWN0KENBRC5DRFcuSUQsIExhdGl0dWRlLCBMb25naXR1ZGUpCgogICMgZml0dGluZyBtb2RlbAogIGZpdCA8LSBrbWVhbnMoZGZfbG9jLCBjbHVzdGVycykKICBmaXQkY2VudGVycyAjIGxvb2sgYXQgY2x1c3RlciBzaXplcyBhbmQgbWVhbnMuIHdhbnQgY2x1c3RlcnMgdG8gYmUgYWJvdXQgZXF1YWwgc2l6ZQogIHJldHVybihmaXQpCn0KCiNtYWtlIGEgcGxvdCB0aGF0IHdpbGwgdGVsbCB5b3UgaG93IG1hbnkgY2x1c3RlcnMgbWlnaHQgd29yayBmb3IgYSBnaXZlbiBkYXRhZnJhbWUKIyB4ID0gYSBkYXRhZnJhbWUKIyBtYXggPSB0aGUgbWF4aW11bSBudW1iZXIgb2YgY2x1c3RlcnMgeW91IHdhbnQgdG8gdHJ5CmZpbmQubnVtLmNsdXN0ZXJzIDwtIGZ1bmN0aW9uKHgsIG1heCkgewogIGlmKG1heCA+IG5yb3coeCkpIHsgc3RvcCgnQ2Fubm90IGZpdCBtb3JlIGNsdXN0ZXJzIHRoYW4gdGhlcmUgYXJlIHJvd3MgaW4gZGF0YWZyYW1lJyl9CiAgZGZfbG9jIDwtIHggJT4lIGRwbHlyOjpzZWxlY3QoQ0FELkNEVy5JRCwgTGF0aXR1ZGUsIExvbmdpdHVkZSkKICB3c3MgPSBjKCkKICBmb3IgKGkgaW4gMTptYXgpIHsKICAgIHdzc1tpXSA8LSBzdW0oa21lYW5zKGRmX2xvYywgY2VudGVycz1pKSR3aXRoaW5zcykKICB9CiAgcGxvdCgxOm1heCwgd3NzLCB0eXBlPSJiIiwgeGxhYj0iTnVtYmVyIG9mIENsdXN0ZXJzIiwKICAgICB5bGFiPSJXaXRoaW4gZ3JvdXBzIHN1bSBvZiBzcXVhcmVzIikKfQoKI3Bsb3QgdGhlIG51bWJlciBvZiBvYnNlcnZhdGlvbnMgaW4gZWFjaCBjbHVzdGVyCiMgeCA9IGEgZml0IG9iamVjdCByZXR1cm5lZCBmcm9tIGttZWFucygpIG9yIHRoZSBmaXQuY2x1c3RlcnMoKSBmdW5jdGlvbiBhYm92ZQpwbG90LmNsdXN0ZXIuc2l6ZXMgPC0gZnVuY3Rpb24oeCkgewogIGNsdXN0ZXIuc2l6ZSA8LSBkYXRhLmZyYW1lKGRhdGEuZnJhbWUoJ2NsdXN0ZXJzJyA9IDE6bnJvdyh4JGNlbnRlcnMpLCB4JHNpemUpKQogIGdncGxvdChkYXRhID0gY2x1c3Rlci5zaXplLCBhZXMoeCA9IGNsdXN0ZXJzLCB5ID0geC5zaXplKSkgKwogIGdlb21fYmFyKHN0YXQgPSAnaWRlbnRpdHknKQp9CmBgYAojI0NsdXN0ZXJpbmcgYnkgdGltZSBvZiBkYXkKYGBge3J9Cm1vcm5pbmcgPC0gZmlsdGVyKGRhdGEsIDYgPD0gYXRfc2NlbmVfdGltZV9ociwgYXRfc2NlbmVfdGltZV9ociA8IDEwICkKbWlkLmRheSA8LSAgZmlsdGVyKGRhdGEsIDEwIDw9IGF0X3NjZW5lX3RpbWVfaHIsIGF0X3NjZW5lX3RpbWVfaHIgPCAxNCApCmFmdGVybm9vbiA8LSAgZmlsdGVyKGRhdGEsIDE0IDw9IGF0X3NjZW5lX3RpbWVfaHIsIGF0X3NjZW5lX3RpbWVfaHIgPCAxOCApCmV2ZW5pbmcgPC0gIGZpbHRlcihkYXRhLCAxOCA8PSBhdF9zY2VuZV90aW1lX2hyLCBhdF9zY2VuZV90aW1lX2hyIDwgMjIgKQpuaWdodCA8LSAgZmlsdGVyKGRhdGEsIDIyIDw9IGF0X3NjZW5lX3RpbWVfaHIgfCBhdF9zY2VuZV90aW1lX2hyIDwgMiApCmVhcmx5Lm1vcm5pbmcgPC0gIGZpbHRlcihkYXRhLCAyIDw9IGF0X3NjZW5lX3RpbWVfaHIsIGF0X3NjZW5lX3RpbWVfaHIgPCA2ICkKCmdnbWFwKHNlYXR0bGUpICsKICBnZW9tX3BvaW50KGRhdGEgPSBtb3JuaW5nLCBhZXMoeCA9IExvbmdpdHVkZSwgeSA9IExhdGl0dWRlKSwgYWxwaGEgPSAwLjUpCgpnZ21hcChzZWF0dGxlKSArCiAgZ2VvbV9wb2ludChkYXRhID0gbWlkLmRheSwgYWVzKHggPSBMb25naXR1ZGUsIHkgPSBMYXRpdHVkZSksIGFscGhhID0gMC41KQoKZ2dtYXAoc2VhdHRsZSkgKwogIGdlb21fcG9pbnQoZGF0YSA9IGFmdGVybm9vbiwgYWVzKHggPSBMb25naXR1ZGUsIHkgPSBMYXRpdHVkZSksIGFscGhhID0gMC41KQoKZ2dtYXAoc2VhdHRsZSkgKwogIGdlb21fcG9pbnQoZGF0YSA9IGV2ZW5pbmcsIGFlcyh4ID0gTG9uZ2l0dWRlLCB5ID0gTGF0aXR1ZGUpLCBhbHBoYSA9IDAuNSkKCmdnbWFwKHNlYXR0bGUpICsKICBnZW9tX3BvaW50KGRhdGEgPSBuaWdodCwgYWVzKHggPSBMb25naXR1ZGUsIHkgPSBMYXRpdHVkZSksIGFscGhhID0gMC41KQoKZ2dtYXAoc2VhdHRsZSkgKwogIGdlb21fcG9pbnQoZGF0YSA9IGVhcmx5Lm1vcm5pbmcsIGFlcyh4ID0gTG9uZ2l0dWRlLCB5ID0gTGF0aXR1ZGUpLCBhbHBoYSA9IDAuNSkKCmxlbmd0aHMgPC0gYyhucm93KG1vcm5pbmcpLCBucm93KG1pZC5kYXkpLCBucm93KGFmdGVybm9vbiksIG5yb3coZXZlbmluZyksIG5yb3cobmlnaHQpLCBucm93KGVhcmx5Lm1vcm5pbmcpKQpuYW1lcyA8LSBjKCdNb3JuaW5nXG42OjAwIC0gOTo1OScsICdNaWQtZGF5XG4xMDowMCAtIDE6NTknLCAnQWZ0ZXJub29uXG4yOjAwIC0gNTo1OScsICdFdmVuaW5nXG42OjAwIC0gOTo1OScsICdOaWdodFxuMTA6MDAgLSAxOjU5JywgJ0Vhcmx5IE1vcm5pbmdcbjI6MDAgLSA1OjU5JykKYnkudG9kIDwtIGRhdGEuZnJhbWUoJ1RPRCcgPSBuYW1lcywgJ0NvdW50LkNyaW1lcycgPSBsZW5ndGhzKQpieS50b2QkVE9EID0gZmFjdG9yKGJ5LnRvZCRUT0QsIGxldmVscyA9IGJ5LnRvZCRUT0QpCgpnZ3Bsb3QoYnkudG9kLCBhZXMoeCA9IFRPRCwgeSA9IENvdW50LkNyaW1lcykpICsKICBnZW9tX2hpc3RvZ3JhbShzdGF0ID0gJ2lkZW50aXR5JykKCiMgZmluZCB0aGUgbW9kZSBvZiBudW1lcmljL2NoYXJhY3RlciBkYXRhCk1vZGUgPC0gZnVuY3Rpb24oeCkgewogIHV4IDwtIHVuaXF1ZSh4KQogIHRhYiA8LSB0YWJ1bGF0ZShtYXRjaCh4LCB1eCkpOyB1eFt0YWIgPT0gbWF4KHRhYildCn0KCnRvZC5tZWFuIDwtIG1lYW4oZGF0YSRhdF9zY2VuZV90aW1lX2hyKQp0b2QubWVkIDwtIG1lZGlhbihkYXRhJGF0X3NjZW5lX3RpbWVfaHIpCnRvZC5tZWFuCnRvZC5tZWQKTW9kZShkYXRhJGF0X3NjZW5lX3RpbWVfaHIpCgojV2hhdCBpcyB0aGUgbW9zdCBjb21tb24gY3JpbWUgY29tbWl0dGVkIGF0IGVhY2ggcGVyaW9kPwpNb2RlKG1vcm5pbmckRXZlbnQuQ2xlYXJhbmNlLkRlc2NyaXB0aW9uKQpNb2RlKG1pZC5kYXkkRXZlbnQuQ2xlYXJhbmNlLkRlc2NyaXB0aW9uKQpNb2RlKGFmdGVybm9vbiRFdmVudC5DbGVhcmFuY2UuRGVzY3JpcHRpb24pCk1vZGUoZXZlbmluZyRFdmVudC5DbGVhcmFuY2UuRGVzY3JpcHRpb24pCk1vZGUobmlnaHQkRXZlbnQuQ2xlYXJhbmNlLkRlc2NyaXB0aW9uKQpNb2RlKGVhcmx5Lm1vcm5pbmckRXZlbnQuQ2xlYXJhbmNlLkRlc2NyaXB0aW9uKQoKI2ZpdCBrbWVhbnMgY2x1c3RlcmluZyB0byBlYWNoIHRpbWUgcGVyaW9kLgpucm93KG1vcm5pbmcpCmZpbmQubnVtLmNsdXN0ZXJzKG1vcm5pbmcsIDEwKQpmaXQgPC0gZml0LmNsdXN0ZXJzKG1vcm5pbmcsIDEwKQpnZ21hcChzZWF0dGxlKSArCiAgZ2VvbV9wb2ludChkYXRhID0gYXMuZGF0YS5mcmFtZShmaXQkY2VudGVycyksIGFlcyh4ID0gTG9uZ2l0dWRlLCB5ID0gTGF0aXR1ZGUpLCBhbHBoYSA9IDAuNSkKIyBsb29raW5nIGF0IGNsdXN0ZXIgbWVhbnMKcGxvdC5jbHVzdGVyLnNpemVzKGZpdCkKCmZpbmQubnVtLmNsdXN0ZXJzKGFmdGVybm9vbiwgMTApCmZpdCA8LSBmaXQuY2x1c3RlcnMobWlkLmRheSwgMTApCmdnbWFwKHNlYXR0bGUpICsKICBnZW9tX3BvaW50KGRhdGEgPSBhcy5kYXRhLmZyYW1lKGZpdCRjZW50ZXJzKSwgYWVzKHggPSBMb25naXR1ZGUsIHkgPSBMYXRpdHVkZSksIGFscGhhID0gMC41KQojIGxvb2tpbmcgYXQgY2x1c3RlciBtZWFucwpwbG90LmNsdXN0ZXIuc2l6ZXMoZml0KQoKbnJvdyhhZnRlcm5vb24pCmZpbmQubnVtLmNsdXN0ZXJzKGFmdGVybm9vbiwgMTApCmZpdCA8LSBmaXQuY2x1c3RlcnMoYWZ0ZXJub29uLCAxMCkKZ2dtYXAoc2VhdHRsZSkgKwogIGdlb21fcG9pbnQoZGF0YSA9IGFzLmRhdGEuZnJhbWUoZml0JGNlbnRlcnMpLCBhZXMoeCA9IExvbmdpdHVkZSwgeSA9IExhdGl0dWRlKSwgYWxwaGEgPSAwLjUpCiMgbG9va2luZyBhdCBjbHVzdGVyIG1lYW5zCnBsb3QuY2x1c3Rlci5zaXplcyhmaXQpCgpmaW5kLm51bS5jbHVzdGVycyhldmVuaW5nLCAxMCkKZml0IDwtIGZpdC5jbHVzdGVycyhldmVuaW5nLCAxMCkKZ2dtYXAoc2VhdHRsZSkgKwogIGdlb21fcG9pbnQoZGF0YSA9IGFzLmRhdGEuZnJhbWUoZml0JGNlbnRlcnMpLCBhZXMoeCA9IExvbmdpdHVkZSwgeSA9IExhdGl0dWRlKSwgYWxwaGEgPSAwLjUpCiMgbG9va2luZyBhdCBjbHVzdGVyIG1lYW5zCnBsb3QuY2x1c3Rlci5zaXplcyhmaXQpCgpmaW5kLm51bS5jbHVzdGVycyhuaWdodCwgMTApCmZpdCA8LSBmaXQuY2x1c3RlcnMobmlnaHQsIDEwKQpnZ21hcChzZWF0dGxlKSArCiAgZ2VvbV9wb2ludChkYXRhID0gYXMuZGF0YS5mcmFtZShmaXQkY2VudGVycyksIGFlcyh4ID0gTG9uZ2l0dWRlLCB5ID0gTGF0aXR1ZGUpLCBhbHBoYSA9IDAuNSkKIyBsb29raW5nIGF0IGNsdXN0ZXIgbWVhbnMKcGxvdC5jbHVzdGVyLnNpemVzKGZpdCkKCmBgYAoKYGBge3J9CiN0YWtlIG91dCBnZW5lcmFsIGNyaXNpcyBjb21wbGFpbnQgLSBnZW5lcmFsCmRhdGEgPC0gZmlsdGVyKGRhdGEsIEV2ZW50LkNsZWFyYW5jZS5EZXNjcmlwdGlvbiAhPSAnQ1JJU0lTIENPTVBMQUlOVCAtIEdFTkVSQUwnKQoKbW9ybmluZyA8LSBmaWx0ZXIoZGF0YSwgNiA8PSBhdF9zY2VuZV90aW1lX2hyLCBhdF9zY2VuZV90aW1lX2hyIDwgMTAgKQptaWQuZGF5IDwtICBmaWx0ZXIoZGF0YSwgMTAgPD0gYXRfc2NlbmVfdGltZV9ociwgYXRfc2NlbmVfdGltZV9ociA8IDE0ICkKYWZ0ZXJub29uIDwtICBmaWx0ZXIoZGF0YSwgMTQgPD0gYXRfc2NlbmVfdGltZV9ociwgYXRfc2NlbmVfdGltZV9ociA8IDE4ICkKZXZlbmluZyA8LSAgZmlsdGVyKGRhdGEsIDE4IDw9IGF0X3NjZW5lX3RpbWVfaHIsIGF0X3NjZW5lX3RpbWVfaHIgPCAyMiApCm5pZ2h0IDwtICBmaWx0ZXIoZGF0YSwgMjIgPD0gYXRfc2NlbmVfdGltZV9ociB8IGF0X3NjZW5lX3RpbWVfaHIgPCAyICkKZWFybHkubW9ybmluZyA8LSAgZmlsdGVyKGRhdGEsIDIgPD0gYXRfc2NlbmVfdGltZV9ociwgYXRfc2NlbmVfdGltZV9ociA8IDYgKQoKZ2dtYXAoc2VhdHRsZSkgKwogIGdlb21fcG9pbnQoZGF0YSA9IG1vcm5pbmcsIGFlcyh4ID0gTG9uZ2l0dWRlLCB5ID0gTGF0aXR1ZGUpLCBhbHBoYSA9IDAuNSkKCmdnbWFwKHNlYXR0bGUpICsKICBnZW9tX3BvaW50KGRhdGEgPSBtaWQuZGF5LCBhZXMoeCA9IExvbmdpdHVkZSwgeSA9IExhdGl0dWRlKSwgYWxwaGEgPSAwLjUpCgpnZ21hcChzZWF0dGxlKSArCiAgZ2VvbV9wb2ludChkYXRhID0gYWZ0ZXJub29uLCBhZXMoeCA9IExvbmdpdHVkZSwgeSA9IExhdGl0dWRlKSwgYWxwaGEgPSAwLjUpCgpnZ21hcChzZWF0dGxlKSArCiAgZ2VvbV9wb2ludChkYXRhID0gZXZlbmluZywgYWVzKHggPSBMb25naXR1ZGUsIHkgPSBMYXRpdHVkZSksIGFscGhhID0gMC41KQoKZ2dtYXAoc2VhdHRsZSkgKwogIGdlb21fcG9pbnQoZGF0YSA9IG5pZ2h0LCBhZXMoeCA9IExvbmdpdHVkZSwgeSA9IExhdGl0dWRlKSwgYWxwaGEgPSAwLjUpCgpnZ21hcChzZWF0dGxlKSArCiAgZ2VvbV9wb2ludChkYXRhID0gZWFybHkubW9ybmluZywgYWVzKHggPSBMb25naXR1ZGUsIHkgPSBMYXRpdHVkZSksIGFscGhhID0gMC41KQoKbGVuZ3RocyA8LSBjKG5yb3cobW9ybmluZyksIG5yb3cobWlkLmRheSksIG5yb3coYWZ0ZXJub29uKSwgbnJvdyhldmVuaW5nKSwgbnJvdyhuaWdodCksIG5yb3coZWFybHkubW9ybmluZykpCm5hbWVzIDwtIGMoJ01vcm5pbmdcbjY6MDAgLSA5OjU5JywgJ01pZC1kYXlcbjEwOjAwIC0gMTo1OScsICdBZnRlcm5vb25cbjI6MDAgLSA1OjU5JywgJ0V2ZW5pbmdcbjY6MDAgLSA5OjU5JywgJ05pZ2h0XG4xMDowMCAtIDE6NTknLCAnRWFybHkgTW9ybmluZ1xuMjowMCAtIDU6NTknKQpieS50b2QgPC0gZGF0YS5mcmFtZSgnVE9EJyA9IG5hbWVzLCAnQ291bnQuQ3JpbWVzJyA9IGxlbmd0aHMpCmJ5LnRvZCRUT0QgPSBmYWN0b3IoYnkudG9kJFRPRCwgbGV2ZWxzID0gYnkudG9kJFRPRCkKCmdncGxvdChieS50b2QsIGFlcyh4ID0gVE9ELCB5ID0gQ291bnQuQ3JpbWVzKSkgKwogIGdlb21faGlzdG9ncmFtKHN0YXQgPSAnaWRlbnRpdHknKQoKIyBmaW5kIHRoZSBtb2RlIG9mIG51bWVyaWMvY2hhcmFjdGVyIGRhdGEKTW9kZSA8LSBmdW5jdGlvbih4KSB7CiAgdXggPC0gdW5pcXVlKHgpCiAgdGFiIDwtIHRhYnVsYXRlKG1hdGNoKHgsIHV4KSk7IHV4W3RhYiA9PSBtYXgodGFiKV0KfQoKdG9kLm1lYW4gPC0gbWVhbihkYXRhJGF0X3NjZW5lX3RpbWVfaHIpCnRvZC5tZWQgPC0gbWVkaWFuKGRhdGEkYXRfc2NlbmVfdGltZV9ocikKdG9kLm1lYW4KdG9kLm1lZApNb2RlKGRhdGEkYXRfc2NlbmVfdGltZV9ocikKCiNXaGF0IGlzIHRoZSBtb3N0IGNvbW1vbiBjcmltZSBjb21taXR0ZWQgYXQgZWFjaCBwZXJpb2Q/Ck1vZGUobW9ybmluZyRFdmVudC5DbGVhcmFuY2UuRGVzY3JpcHRpb24pCk1vZGUobWlkLmRheSRFdmVudC5DbGVhcmFuY2UuRGVzY3JpcHRpb24pCk1vZGUoYWZ0ZXJub29uJEV2ZW50LkNsZWFyYW5jZS5EZXNjcmlwdGlvbikKTW9kZShldmVuaW5nJEV2ZW50LkNsZWFyYW5jZS5EZXNjcmlwdGlvbikKTW9kZShuaWdodCRFdmVudC5DbGVhcmFuY2UuRGVzY3JpcHRpb24pCk1vZGUoZWFybHkubW9ybmluZyRFdmVudC5DbGVhcmFuY2UuRGVzY3JpcHRpb24pCgojZml0IGttZWFucyBjbHVzdGVyaW5nIHRvIGVhY2ggdGltZSBwZXJpb2QuCm5yb3cobW9ybmluZykKZmluZC5udW0uY2x1c3RlcnMobW9ybmluZywgMTApCmZpdCA8LSBmaXQuY2x1c3RlcnMobW9ybmluZywgMTApCmdnbWFwKHNlYXR0bGUpICsKICBnZW9tX3BvaW50KGRhdGEgPSBhcy5kYXRhLmZyYW1lKGZpdCRjZW50ZXJzKSwgYWVzKHggPSBMb25naXR1ZGUsIHkgPSBMYXRpdHVkZSksIGFscGhhID0gMC41KQojIGxvb2tpbmcgYXQgY2x1c3RlciBtZWFucwpwbG90LmNsdXN0ZXIuc2l6ZXMoZml0KQoKZmluZC5udW0uY2x1c3RlcnMoYWZ0ZXJub29uLCAxMCkKZml0IDwtIGZpdC5jbHVzdGVycyhtaWQuZGF5LCAxMCkKZ2dtYXAoc2VhdHRsZSkgKwogIGdlb21fcG9pbnQoZGF0YSA9IGFzLmRhdGEuZnJhbWUoZml0JGNlbnRlcnMpLCBhZXMoeCA9IExvbmdpdHVkZSwgeSA9IExhdGl0dWRlKSwgYWxwaGEgPSAwLjUpCiMgbG9va2luZyBhdCBjbHVzdGVyIG1lYW5zCnBsb3QuY2x1c3Rlci5zaXplcyhmaXQpCgpucm93KGFmdGVybm9vbikKZmluZC5udW0uY2x1c3RlcnMoYWZ0ZXJub29uLCAxMCkKZml0IDwtIGZpdC5jbHVzdGVycyhhZnRlcm5vb24sIDEwKQpnZ21hcChzZWF0dGxlKSArCiAgZ2VvbV9wb2ludChkYXRhID0gYXMuZGF0YS5mcmFtZShmaXQkY2VudGVycyksIGFlcyh4ID0gTG9uZ2l0dWRlLCB5ID0gTGF0aXR1ZGUpLCBhbHBoYSA9IDAuNSkKIyBsb29raW5nIGF0IGNsdXN0ZXIgbWVhbnMKcGxvdC5jbHVzdGVyLnNpemVzKGZpdCkKCmZpbmQubnVtLmNsdXN0ZXJzKGV2ZW5pbmcsIDEwKQpmaXQgPC0gZml0LmNsdXN0ZXJzKGV2ZW5pbmcsIDEwKQpnZ21hcChzZWF0dGxlKSArCiAgZ2VvbV9wb2ludChkYXRhID0gYXMuZGF0YS5mcmFtZShmaXQkY2VudGVycyksIGFlcyh4ID0gTG9uZ2l0dWRlLCB5ID0gTGF0aXR1ZGUpLCBhbHBoYSA9IDAuNSkKIyBsb29raW5nIGF0IGNsdXN0ZXIgbWVhbnMKcGxvdC5jbHVzdGVyLnNpemVzKGZpdCkKCmZpbmQubnVtLmNsdXN0ZXJzKG5pZ2h0LCAxMCkKZml0IDwtIGZpdC5jbHVzdGVycyhuaWdodCwgMTApCmdnbWFwKHNlYXR0bGUpICsKICBnZW9tX3BvaW50KGRhdGEgPSBhcy5kYXRhLmZyYW1lKGZpdCRjZW50ZXJzKSwgYWVzKHggPSBMb25naXR1ZGUsIHkgPSBMYXRpdHVkZSksIGFscGhhID0gMC41KQojIGxvb2tpbmcgYXQgY2x1c3RlciBtZWFucwpwbG90LmNsdXN0ZXIuc2l6ZXMoZml0KQpgYGAKCg==